package com.alan.learn.common;

import org.apache.commons.codec.binary.Hex;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public final class SignatureUtils {

    private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
    private static final String ENCRYPTION_ALGORITHM = "SHA-1";
    private static final boolean DEFAULT_PUB = true;

    private SignatureUtils() {
    }

    public static String toHex(byte[] data) {
        return new String(Hex.encodeHex(data));
    }

    public static String bytesToHexString(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }

    public static byte[] hexStringToBytes(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }

    public static String digest(String strSrc) {
        return digest(strSrc, DEFAULT_PUB);
    }

    public static String digest(String strSrc, boolean pub) {
        return digest(strSrc, "MD5", pub);
    }

    public static String digest(String strSrc, String encName) {
        return digest(strSrc, encName, DEFAULT_PUB);
    }


    /**
     * 使用指定算法生成消息摘要，默认是md5
     *
     * @param strSrc  , a string will be encrypted; <br/>
     * @param encName , the algorithm name will be used, dafault to "MD5"; <br/>
     * @return
     */
    public static String digest(String strSrc, String encName, boolean pub) {
        MessageDigest md = null;
        String strDes = null;
        byte[] bt = strSrc.getBytes();
        try {
            if (encName == null || encName.equals("")) {
                encName = "MD5";
            }
            md = MessageDigest.getInstance(encName);
            md.update(bt);
            byte[] digest = md.digest();
            strDes = (pub) ? toHex(digest) : bytesToHexString(digest);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Invalid algorithm: " + encName);
        }
        return strDes;
    }

    public static String signature(String key, String digest, long millis) {
        return signature(key, digest, millis, DEFAULT_PUB);
    }

    public static String signature(String key, String digest, long millis, boolean pub) {
        String timestamp = String.valueOf(millis);
        String signature = null;
        if (isNotBlank(key) && isNotBlank(timestamp)) {
            String value = getSort(key, digest, String.valueOf(millis));
            signature = digest(value, ENCRYPTION_ALGORITHM, pub);
        }
        return signature;
    }

    public static boolean isNotBlank(String str) {
        return !isBlank(str);
    }

    public static boolean isBlank(String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((!Character.isWhitespace(str.charAt(i)))) {
                return false;
            }
        }
        return true;
    }

    /**
     * 文件排序 按照字典序逆序拼接参数
     *
     * @param params 需要排序的数据
     * @return
     */
    public static String getSort(String... params) {
        List <String> srcList = new ArrayList <String>(Arrays.asList(params));
        // 按照字典序逆序拼接参数
        Arrays.sort(params);
        srcList.sort(String.CASE_INSENSITIVE_ORDER);
        Collections.reverse(srcList);
        StringBuilder sb = new StringBuilder();
        for (String aSrcList : srcList) {
            sb.append(aSrcList);
        }
        return sb.toString();
    }
}
